import {NPC} from './NPC.js';
import {GLTFLoader} from '../libs/three137/GLTFLoader.js';
import {DRACOLoader} from '../libs/three137/DRACOLoader.js';
import {Skeleton, Raycaster, BufferGeometry, Vector3, Line} from '../libs/three137/three.module.js';
import { urls } from '../assets/store.js';
let id =0 ;
class NPCHandler{
    constructor( game ){
        this.game = game;
		this.loadingBar = this.game.loadingBar;
        // this.waypoints = game.waypoints;
        this.load();
		this.initMouseHandler();
	}

	initMouseHandler(){
		const raycaster = new Raycaster();
    	this.game.renderer.domElement.addEventListener( 'click', raycast, false );
			
    	const self = this;
    	const mouse = { x:0, y:0 };
    	
    	function raycast(e){
    		
			mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
			mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;

			//2. set the picking ray from the camera position and mouse coordinates
			raycaster.setFromCamera( mouse, self.game.camera );    

			//3. compute intersections
			const intersects = raycaster.intersectObject( self.game.navMesh );
			// 选中npc 即开始初始化
			if (intersects.length>0){
				const pt = intersects[0].point;
				// console.log(pt);
				// self.npcs[0].newPath(pt, true);
			}	
		}
    }

    load(){
        const loader = new GLTFLoader( );
		const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath( '../libs/three137/draco/' );
        loader.setDRACOLoader( dracoLoader );
        this.loadingBar.visible = true;
		
		// Load a GLTF resource
		loader.load(
			// resource URL
			urls.swotGuy_glb,
			// called when the resource is loaded
			gltf => {
				if (this.game.pathfinder){
					
					this.initNPCs(gltf);
				}else{
					this.gltf = gltf;
				}
			},
			// called while loading is progressing
			xhr => {

				this.loadingBar.update( 'swat-guy', xhr.loaded, xhr.total );

			},
			// called when loading has errors
			err => {

				console.error( err );

			}
		);
	}
    
	initNPCs(gltf = this.gltf){
		const gltfs = [gltf]
        this.waypoints = game.waypoints;// 因为这个方法是在 场景和人物都加载完毕之后才调用，所以这里赋值就没问题了

		this.npcs = [] ;
		for ( let i= 0; i < 5; i++){ 
			gltfs.push(this.cloneGLTF(gltf))
		}
		gltfs.forEach((gltf)=> { 
			let rifle, aim ;
			const obj = gltf.scene ; 
			obj.traverse((child)=> {
				if(child.isMesh){ 
					child.castShadow = true ;
					child.frustumCulled = false ; // 关掉这个检查的目的是什么呢，检查在可视区域内会改变什么呢
					child.material.transparent = true ; // 避免在后面使用透明度动画时的卡顿
					if(child.name.includes('Rifle')) rifle = child
				}
			})
			if(rifle){ 
				const geo = new BufferGeometry().setFromPoints([new Vector3(0), new Vector3(1,0,0) ]);
				const line = new Line(geo) ;
				line.name = 'aim' ;
				line.scale.x =50 ;

				rifle.add(line) ;
				line.position.set(0,0,.5) ;
				aim = line ;
				line.visible =false ;
			}

			const options = {
				object:obj ,
				speed:.9 ,
				app:this.game ,
				showPath:false ,
				animations: gltf.animations,
				zone: 'factory' ,
				name: 'swat-guy'+ id ,
				waypoints:this.waypoints,
				rifle ,
				aim

			}
			id++ ;
			const npc = new NPC(options)

			npc.object.position.copy(this.randomWaypoint) // 必须位于 navMesh之上
			npc.newPath(this.randomWaypoint)
			this.npcs.push(npc) ; 
		})
		// this.loadingBar.visible = !this.loadingBar.loaded ; // 这里是加载npc完成的地方
		this.ready = true ;
		this.game.startRendering()
		// if(this.game.user.ready && !this.game.bulletHandler)  this.game.bulletHandler = new BulletHandler(this.game) ;

	}

	reset(){ 
		this.npcs.forEach((npc)=>npc.reset())
	}
	get randomWaypoint(){ 
		let id  = Math.floor(Math.random()* this.waypoints.length) ;

		return   this.waypoints[id]
	}
		// 这个得自己实现啊 看来scene的clone  
	cloneGLTF(gltf){         
	
		const clone = {
			animations: gltf.animations,
			scene: gltf.scene.clone(true)
		  };
		
		const skinnedMeshes = {};
		
		gltf.scene.traverse(node => {
			if (node.isSkinnedMesh) {
			  skinnedMeshes[node.name] = node;
			}
			if( node.material){ 
				node.material = node.material.clone()
			}
		});
		
		const cloneBones = {};
		const cloneSkinnedMeshes = {};
		
		clone.scene.traverse(node => {
			if (node.isBone) {
			  cloneBones[node.name] = node;
			}
			if (node.isSkinnedMesh) {
			  cloneSkinnedMeshes[node.name] = node;
			}
		});
		
		for (let name in skinnedMeshes) {
			const skinnedMesh = skinnedMeshes[name];
			const skeleton = skinnedMesh.skeleton;
			const cloneSkinnedMesh = cloneSkinnedMeshes[name];
			const orderedCloneBones = [];
			for (let i = 0; i < skeleton.bones.length; ++i) {
				const cloneBone = cloneBones[skeleton.bones[i].name];
				orderedCloneBones.push(cloneBone);
			}
			cloneSkinnedMesh.bind(
				new Skeleton(orderedCloneBones, skeleton.boneInverses),
				cloneSkinnedMesh.matrixWorld);
		}
		
		return clone;

	}
    update(dt){
        if (this.npcs) this.npcs.forEach( npc => npc.update(dt) );
    }
}

export { NPCHandler };